package com.lzd.framework.springsecurity.security;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import com.lzd.framework.springsecurity.common.util.Json;
import com.lzd.framework.springsecurity.security.Authentication.MyAuthenticationToken;
import com.lzd.framework.springsecurity.security.exception.BadCredentialsExceptionBase;
import com.lzd.framework.springsecurity.security.exception.UsernameNotFoundExceptionBase;
import com.lzd.framework.springsecurity.service.MyUserDetailsService;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter{
	
    private MyUserDetailsService userDetailsService;

    private PasswordEncoder passwordEncoder;
    @Autowired
    public LoginAuthenticationFilter(MyUserDetailsService userDetailsService, PasswordEncoder passwordEncoder) {
        super("/login");
        // POST Method http://127.0.0.1:8000/login?grant_type=admin&principal=&credentials=
        this.userDetailsService = userDetailsService;
        this.passwordEncoder = passwordEncoder;
    }
    
    /***
     * 执行具体的用户密码校验等
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    	log.info("attemptAuthentication:{}",request.getQueryString());
        String requestBody = getStringFromStream(request);

        log.info("request：----1{}---------2{}------3{}----------",request.getQueryString(),request.getRequestURL(),requestBody);        
        if (StrUtil.isBlank(requestBody)) {
            throw new AuthenticationServiceException("无法获取输入信息");
        }

        MyAuthenticationToken adminAuthenticationToken  =  Json.parseObject(requestBody, MyAuthenticationToken.class);
        String username = adminAuthenticationToken.getPrincipal() == null?"NONE_PROVIDED":adminAuthenticationToken.getName();
        UserDetails user;
        try {
            user = userDetailsService.loadUserByUsername(username);
        } catch (UsernameNotFoundExceptionBase e) {
            throw new UsernameNotFoundExceptionBase("账号或密码不正确");
        }    	
        String encodedPassword = user.getPassword();
        String rawPassword = adminAuthenticationToken.getCredentials().toString();

        // 密码不正确
        if (!passwordEncoder.matches(rawPassword,encodedPassword)){
            throw new BadCredentialsExceptionBase("账号或密码不正确");
        }

        if (!user.isEnabled()) {
            throw new UsernameNotFoundExceptionBase("账号已被锁定,请联系管理员");
        }
        //NOTICE 此处必须获得Authorities，因此默认的AuthenticationProvider要求有Authorities
        MyAuthenticationToken result = new MyAuthenticationToken(user, adminAuthenticationToken.getCredentials(),user.getAuthorities());
        result.setDetails(adminAuthenticationToken.getDetails());

        return result;
    }
    
    private String getStringFromStream(HttpServletRequest req) {
        ServletInputStream is;
        try {
            is = req.getInputStream();
            int nRead = 1;
            int nTotalRead = 0;
            byte[] bytes = new byte[10240];
            while (nRead > 0) {
                nRead = is.read(bytes, nTotalRead, bytes.length - nTotalRead);
                if (nRead > 0) {
                    nTotalRead = nTotalRead + nRead;
                }
            }
            return new String(bytes, 0, nTotalRead, StandardCharsets.UTF_8);
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
    
    @Override
    @Autowired
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    @Override
    @Autowired
    public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
        super.setAuthenticationSuccessHandler(successHandler);
    }

    @Override
    @Autowired
    public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
        super.setAuthenticationFailureHandler(failureHandler);
    }    
}
